#ifndef PV_H
#define PV_H

#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>
#include <atomic>

/* 代码声明部分 */
class semaphore{ // 信号量类
private:
    std::atomic<int> value; // 信号量值
public:
	std::mutex mtx; // 互斥锁
	std::condition_variable cond; // 条件变量
public:
    semaphore(int v = 1);      // 构造函数
	void operator=(int num);   // 赋值运算符重载
	semaphore & operator+=(int num); // E += num
	semaphore & operator-=(int num); // E -= num
	bool operator==(int num); // E==num
	bool operator<(int num); // S<num 注意顺序 semaphore 在左，数字在右
    bool operator>(int num); // S>num
	bool operator<=(int num);
	bool operator>=(int num);
	friend bool operator==(int num,semaphore &s); 
	friend bool operator<(int num,semaphore &s);
    friend bool operator>(int num,semaphore &s);
	friend bool operator<=(int num,semaphore &s);
	friend bool operator>=(int num,semaphore &s);
};
void P(semaphore &s); // P操作原语
void V(semaphore &s); // V操作原语

bool operator==(int num,semaphore &s); // num == S
bool operator<(int num,semaphore &s); // num < S
bool operator>(int num,semaphore &s); // num > S
bool operator<=(int num,semaphore &s); // num <= S
bool operator>=(int num,semaphore &s); // num >= S


class Lout {
private:
	static std::mutex mtx; // 互斥锁,用于控制输出
public:
	Lout() = default;
	friend void out_start(); // 上锁，开始打印
	friend void out_end();   // 解锁，结束打印
};
void out_start();
void out_end();



/* 代码实现部分 */
void P(semaphore &s){
	std::unique_lock<std::mutex> lock(s.mtx); // 创建互斥锁
	s -= 1;    // 信号量值减一
	if(s < 0){ // 如果信号量值小于0
		s.cond.wait(lock); // 等待
	}
}
void V(semaphore &s){
	std::unique_lock<std::mutex> lock(s.mtx); // 创建互斥锁
	s += 1;    // 信号量值加一
	if(s <= 0){ // 如果信号量值小于等于0
		s.cond.notify_one(); // 通知一个等待的线程
	}
}

semaphore::semaphore(int v) : value(v) {}

void semaphore::operator=(int num) {
    value = num;
}
semaphore & semaphore::operator+=(int num) {
    value += num;
    return *this;
}
semaphore & semaphore::operator-=(int num) {
    value -= num;
    return *this;
}

bool semaphore::operator==(int num) {
    return value == num;
}

bool operator==(int num,semaphore &s) {
    return num == s.value;
}
bool semaphore::operator<(int num) {
    return value < num;
}
bool semaphore::operator>(int num) {
    return value > num;
}

bool semaphore::operator<=(int num){
    return value <= num;
}
bool semaphore::operator>=(int num){
    return value >= num;
}

bool operator<(int num,semaphore &s){
    return num < s.value;
}
bool operator>(int num,semaphore &s){
    return num > s.value;
}

bool operator<=(int num,semaphore &s){
    return num <= s.value;
}

bool operator>=(int num,semaphore &s){
    return num >= s.value;
}

std::mutex Lout::mtx;

void out_start() {
    Lout::mtx.lock();
}

void out_end() {
    Lout::mtx.unlock();
}

#endif // PV_H